package com.blue.wechat.invoke;

import java.text.MessageFormat;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.blue.core.dict.HttpMethod;
import com.blue.http.client.HttpInvoker;
import com.blue.wechat.cache.AccessTokenCache;
import com.blue.wechat.cache.Wechat;
import com.blue.wechat.cache.WechatCache;
import com.blue.wechat.invoke.model.AccessToken;
import com.blue.wechat.invoke.model.ErrorMsg;

/**
 * 微信接口调用抽象类
 * 
 * @author zhengj
 * @since 1.0 2017年1月25日
 */
public abstract class BaseInvoker<T> implements Invoker<T>
{
	private static Logger logger = LoggerFactory.getLogger(BaseInvoker.class);
	
	@Resource
	protected HttpInvoker httpInvoker;
	@Resource
	protected WechatContainer wechatContainer;
	@Resource
	protected WechatCache wechatCache;
	@Resource
	protected AccessTokenCache accessTokenCache; 
	
	public BaseInvoker()
	{
	}
	
	@Override
	public final T invoke(String code, Object post, String...get)
	{
		Wechat wechat = wechatCache.getByCode(code);
		if (wechat == null)
			throw InvokeException.getException(InvokeException.WECHAT_NOT_FOUND + code);
		
		String resp = this.invoke(wechat, post, get);
		if (resp.contains("\"errcode\":"))
		{
			ErrorMsg error = JSON.parseObject(resp, ErrorMsg.class);
			if ("40014".equals(error.getErrcode()) || "40001".equals(error.getErrcode()) || "42001".equals(error.getErrcode()))
			{
				logger.warn("access_token 过期");
				accessTokenCache.delete(wechat.getCode());
				resp = this.invoke(wechat, post, get);
			}
			else if (!"0".equals(error.getErrcode())) // 其它失败信息
			{
				this.handleError(error, wechat);
				return null;
			}
		}
		return this.handleSuccess(resp, wechat);
	}
	
	private String invoke(Wechat wechat, Object post, String...get)
	{
		WechatInvoker invoker = this.getInvoker();
		String token = this.getAccessToken(wechat.getCode());
		Object[] params = new Object[get.length + 1];
		params[0] = token;
		for (int i = 0; i < get.length; i++)
		{
			params[i+1] = get[i];
		}
		String url = MessageFormat.format(invoker.getUrl(), params);
		long start = System.currentTimeMillis();
		String resp = null;
		
		try
		{
			resp = this.invoke(url, invoker.getMethod(), post);
			WechatInvokeUtil.log(wechat.getName(), invoker.getName(), url, StringUtils.join(get, ","), post, (int)(System.currentTimeMillis() - start), resp, null);
			return resp;
		}
		catch (Exception e)
		{
			WechatInvokeUtil.log(wechat.getName(), invoker.getName(), url, StringUtils.join(get, ","), post, (int)(System.currentTimeMillis() - start), e.getMessage(), e);
			throw InvokeException.getException(InvokeException.ERROR + invoker.getName());
		}
	}
	
	protected String invoke(String url, HttpMethod method, Object post) throws Exception
	{
		String resp = null;
		if (method == HttpMethod.GET)
		{
			resp = httpInvoker.get(url);
		}
		else
		{
			String json = null;
			if (post != null)
			{
				json = WechatInvokeUtil.toString(post);
			}
			resp = httpInvoker.post(url, json);
		}
		return resp;
	}
	
	/**
	 * 获取微信接口配置
	 * 
	 * @return 微信接口配置
	 */
	protected abstract WechatInvoker getInvoker();
	
	/**
	 * 错误处理，默认抛出异常
	 * 
	 * @param error 错误信息
	 * @param wechat 微信信息
	 */
	protected void handleError(ErrorMsg error, Wechat wechat)
	{
		throw InvokeException.getException(InvokeException.ERROR + error.getErrmsg());
	}

	/**
	 * 成功处理
	 * 
	 * @param resp HTTP返回信息
	 * @param weixinId 微信编号
	 * @return 成功提示信息
	 */
	protected abstract T handleSuccess(String resp, Wechat wechat);
	
	protected String getAccessToken(String code)
	{
		String token = accessTokenCache.getTokenByCode(code);
		if (token != null && !token.isEmpty())
			return token;
			
		AccessToken at = wechatContainer.invoke(code, WechatInvoker.ACCESS_TOKEN, null);
		token = at.getAccessToken();
		logger.info("TOKEN：{}", token);
		return token;
	}
	
	
	
}
